from sanic import Blueprint

from view.conf import battledic, battleground, battle_wsdic, \
                        online_wsdic, waitdic, solodic, namelist
from play.battle import *
from mysql.DB_api import db_insert
from play.play_alone import AI_chessing, dumps_


bp1 = Blueprint('bp1')
battlinglist = {}  # bothside:battledata 双人对战数据
battlinglist_solo = {}  # you:battledata 人机对战数据

break_list = []


@bp1.websocket('/register')
async def register(request, ws):
    _quit = 0
    your_ip = request.ip
    try:
        waitdic.pop(your_ip)
    except:
        pass    # <<<<<<<<<<<<<<<<<<<<
    name = await ws.recv()
    _namelist = []
    for key, value in namelist.items():
        _namelist.append(value)
    if _namelist.count(name) == 0 and name != 'null' and name:
        namelist[your_ip] = name
        await ws.send('positive')
        print('\n', 'your name:', name)
    else:
        await ws.send('negative')
        print('xxxxxxxxxxx你输入的昵称不合理')


@bp1.websocket('/waiting')
async def waiting(request, ws):
    your_ip = request.ip
    name = False
    try:
        _namelist = []
        name = namelist[your_ip]  # <<<<<<<<<给前端发送重新注册信号
        print('********** ' + name + ' 进入waiting**********')

        for value in namelist.values():
            _namelist.append(value)
        if _namelist.count(name) == 1 and name != 'null' and name:

            # 给所有人广播名单
            waitdic[your_ip] = name      # ip-名字
            online_wsdic[your_ip] = ws  # 将ip与ws绑定
            print('waitdic:', waitdic)
            print('namelist:', namelist, '\n')
            await broadcast_all()
            quit_ = 0
            _oldrt = None
            wait = 0
            while True:
                _blackgoin = 0
                _whitegoin = 0
                _blackquit = 0
                _whitequit = 0
                _sologoin = 0
                _soloquit = 0

                for black, white in battleground.items():
                    if black == name:
                        _oldrt = None
                        _blackgoin = 1
                        battledic[your_ip] = name
                        # print(battledic)
                        await ws.send('yes')
                    if white == name:
                        _oldrt = None
                        _whitegoin = 1
                        battledic[your_ip] = name
                        # print(battledic)
                        await ws.send('yes')

                for i, j in solodic.items():
                    if i == your_ip:
                       _sologoin = 1

                if _sologoin == 1:
                    while True:
                        if your_ip not in solodic:
                            _soloquit = 1
                        if _soloquit == 1:
                            await broadcast_all()
                            print('\n')
                            print('********** ' + name + ' 回到waiting**********')
                            break
                        await asyncio.sleep(1)

                # 开始play后等待状态睡眠,双方
                if _blackgoin == 1:
                    while True:
                        if your_ip not in battledic:
                            _blackquit = 1
                        if _blackquit == 1:
                            await  broadcast_all()  # 给所有人广播名单
                            print('\n')
                            print('********** ' + name + ' 回到waiting**********')
                            break   # 如果从play中退出来则break
                        await asyncio.sleep(1)

                if _whitegoin == 1:
                    while True:
                        if your_ip not in battledic:
                            _whitequit = 1
                        if _whitequit == 1:
                            await  broadcast_all()  # 给所有人广播名单
                            print('\n')
                            print('********** ' + name + ' 回到waiting**********')
                            break
                        await asyncio.sleep(1)

                if quit_ == 1:      # 暂定永久等待
                    break
                if wait == 10:
                    wait = 0    # wait用于控制台显示频率用
                    print('============', name, '正在等待')
                wait += 1
                await asyncio.sleep(0.3)        # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<调整延迟时间以快速开始游戏
                if your_ip in break_list:
                    break
        else:
            print(name, '名字错误!!!')

        if your_ip in break_list:
            break_list.remove(your_ip)
            await ws.send('KeyError!')

    except KeyError:
        print('<<<<<<<<<<<<发生错误,已强制重新注册')
        await ws.send('KeyError!')      # 让前端回到重新注册
    finally:
        try:
            online_wsdic.pop(your_ip)
            namelist.pop(your_ip)
            print('\n')
            print('xxxxxxxxxx\"ip\":' + your_ip + ' \"name\":' + name + '已掉线')
            while True:
                _quit = 0
                if your_ip in waitdic:
                    _quit = 1
                if _quit == 1:
                    break
                await asyncio.sleep(0.1)
            waitdic.pop(your_ip)
            # 给所有人广播名单
            await  broadcast_all()

        except KeyError:
            print('<<<<<<<<<<<<发生错误,已强制重新注册')


@bp1.websocket('/choose')
async def choose(request, ws):
    _list = []  # 制作等待列表
    ip_black = 0
    ip_white = 0
    answer = False
    black = await ws.recv()  # 接收当前用户
    white = await ws.recv()  # 接收他选择的对手

    try:
        for i, j in waitdic.items():  # for循环里最好用i, j
            _list.append(j)
            if black == j:
                ip_black = i
            if white == j:
                ip_white = i
        if _list.count(white) == 1 and _list.count(black) == 1 and white != 'null' and white and white != black:
            # 如果对方在等待列表里
            # 如果自己在等待列表里
            # 如果对手不是自己
            waitdic.pop(ip_black)
            waitdic.pop(ip_white)
            await broadcast_all()  # 将双方名字暂时隐藏

            while True:
                await online_wsdic[ip_white].send('confirm')
                answer = await online_wsdic[ip_white].recv()        # <<<<<<<<<<<<<这里的exception
                print('answer:', answer)

                if namelist.get(ip_black) != black or namelist.get(ip_white) != white:
                    print('//ws.close()')
                    await ws.close()
                # 收到确认消息
                if answer == 'yes':
                    # 如果此时双方任然是合法的
                    battleground[black] = white  # 绑定战斗双方
                    print('\n' + '---------- ' + black + ' VS ' + white + '----------')
                    await online_wsdic[ip_black].send('pass')
                    await online_wsdic[ip_white].send('pass')
                if answer == 'no':
                    await online_wsdic[ip_black].send('nopass')     # <<<<<<<<<<<<<<收到上一次的nopass
                break
        else:
            print('black:', black)
            print('white:', white)
            print('<--你的选择有问题')
    except Exception as e:
        # 让前端回到waiting
        # 黑方意外退出，让白方不要选择yes/no回到等待状态
        # 白方意外退出没有影响
        answer = 'error'
        break_list.append(ip_black)
        break_list.append(ip_white)
    finally:
        if answer == 'no' or answer == 'error':     # 如果没有正常绑定双方则还原waitdic
            print('//还原waitdic')
            waitdic[ip_black] = black
            waitdic[ip_white] = white
            await broadcast_all()


@bp1.websocket('/solo')
async def solo(request, ws):
    your_ip = request.ip
    your_name = await ws.recv()

    if your_ip not in waitdic:
        print('xxxxxxxxxx你不在waitlist中')
        await ws.close()    # 不在waitlist中的选择旧自动关闭ws

    solodic[your_ip] = your_name
    print('\n')
    print('********** ' + your_name + ' 进入solo**********')
    print(your_name, '进入solo')
    print('solodic:', solodic)

    battlinglist_solo[ws] = []
    gt = await ws.recv()
    if gt == 'easy':
        model = 0   # mct
        prt = 'MCTS模型'
    else:
        model = 1   # a-b
        prt = 'a-b剪枝'
    try:
        waitdic.pop(your_ip)
        await broadcast_all()
        while True:
            # battledata里面:<与前端交互>，黑棋（人）是1，白棋（机）是0
            # 人下棋
            print('---------- ' + your_name + ' VS \'' + prt + '\' ----------')
            player = dumps(await ws.recv())
            battlinglist_solo[ws].append(player)
            print(your_name, '玩家下棋:', player)
            flag = check_win(player, battlinglist_solo[ws])
            if flag != -1:
                break

            # 电脑下棋
            AI_chess = await AI_chessing(model, battlinglist_solo[ws])
            AI_chess.append(0)
            battlinglist_solo[ws].append(AI_chess)
            print(your_name, '电脑下棋:', AI_chess)
            flag = check_win(AI_chess, battlinglist_solo[ws])
            print(battlinglist_solo[ws], '\n')
            # 给前端传回电脑下的棋
            _list = []
            for i in AI_chess:
                _list.append(str(i))
                _list.append(',')
            _list.pop()
            rt = ''.join(_list)
            await ws.send('\"' + rt + '\"')
            await asyncio.sleep(0.2)

            # 结束游戏
            if flag != -1:
                break
        if flag == 1:
            print('对战结束!', your_name, '获胜!')
        else:
            print('电脑获胜!')

        db_insert(locations=battlinglist_solo[ws], win=flag)  # 向数据库中写入该盘对句
        await ws.send('battle complete!')

    except KeyError:
        print('你无法选择人机对战，因为你不在等待列表中！')
        print('\n')
    finally:
        print('清理人机列表solodic:', solodic)
        solodic.pop(your_ip)
        battlinglist_solo.pop(ws)
        waitdic[your_ip] = your_name


@bp1.websocket('/play')
async def play(request, ws):
    flag_black = False
    flag_white = False
    _onlyOnce_b = 0
    _onlyOnce_w = 0
    black = None
    ip_black = None
    white = None
    ip_white = None
    bothside = None
    Tom = None
    Jerry = None
    try:
        endbattle = -1
        your_ip = request.ip
        your_name = battledic[your_ip]
        battle_wsdic[your_ip] = ws     # 把当前用户ws添加进来

        # 获取双方的名字
        for key, value in battleground.items():
            if your_name == key or your_name == value:
                black = key     # 根据battledic获得双方的名字, black是主动点击方
                white = value

        bothside = black + white
        battlinglist[bothside] = []
        # 开始下棋前的确认等待(添加等待)
        while True:
            for i, j in battle_wsdic.items():
                if battledic[i] == black and _onlyOnce_b == 0:
                    flag_black = True
                    _onlyOnce_b = 1
                if battledic[i] == white and _onlyOnce_w == 0:
                    flag_white = True
                    _onlyOnce_w = 1

            if flag_white and flag_black:
                print(your_name, '可以开始了')
                break
            else:
                pass
                # print(your_name, '在等待对手确认')
            await asyncio.sleep(1)        # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<调整延迟时间以快速开始游戏
        # 获得双方的ip，这部分只能放在添加等待的后面
        for i, j in battledic.items():
            if j == white:  # 根据battlelist获得双方的ip
                ip_white = i
            if j == black:
                ip_black = i

        # 下棋部分
        Tom = battle_wsdic[ip_black]    # 获得双方的ws对象
        Jerry = battle_wsdic[ip_white]
        while True:
            # tom先下棋
            rec_t = await Tom.recv()
            tom_play = dumps(rec_t)
            if tom_play:
                print(black + ' 下棋', ':', tom_play)
                battlinglist[bothside].append(tom_play)  # 存放有效数据
                endbattle = check_win(tom_play, battlinglist[bothside])  # 判断tom这一步棋赢了没
                await Jerry.send(rec_t)  # 传给jerry 前端传过来的数据，是str型
            # ******************黑方获胜*****************
            if endbattle == 1:
                print('黑色方' + black + '获胜')
                print('战斗数据：', battlinglist[bothside])
                db_insert(locations=battlinglist[bothside], win=endbattle)    # 向数据库中写入该盘对句
                break

            # jerry下棋
            rec_j = await Jerry.recv()
            jerry_play = dumps(rec_j)
            if jerry_play:
                print(white + ' 下棋', ':', jerry_play)    # 显示这个人下的那个子
                battlinglist[bothside].append(jerry_play)
                endbattle = check_win(jerry_play, battlinglist[bothside])
                await Tom.send(rec_j)  # 传给Tom 前端传来的数据，是str型
            # ******************白方获胜*****************
            if endbattle == 0:
                print('白色方' + white + '获胜')
                print('战斗数据：', battlinglist[bothside])
                db_insert(locations=battlinglist[bothside], win=endbattle)    # 向数据库中写入该盘对句
                break
            print(battlinglist[bothside], '\n')
    finally:
        try:
            battleground.pop(black)    # 战斗列表去出这两个人
            battlinglist.pop(bothside)  # 将这一盘的战斗数据清除
            battledic.pop(ip_black)
            battledic.pop(ip_white)
            battle_wsdic.pop(ip_black)
            battle_wsdic.pop(ip_white)
            waitdic[ip_black] = black
            waitdic[ip_white] = white
        except KeyError:
            pass    # 报KeyError错误
        await Tom.send('battle complete!')
        await Jerry.send('battle complete!')


async def broadcast_all():
    broadlist = []
    for i, j in waitdic.items():
        broadlist.append(j)     # 获得名字列
    rt = ','.join(str(i) for i in broadlist)  # 将数组转换成字符串发送
    for i in online_wsdic.values():  # 给所有用户同时更新用户信息界面
        try:  # 加一个try于是不阻塞了~~
            await i.send(rt)
        except:
            print('<<<<<<<<<<<<<<<broad_all部分出错')
            continue
